<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0,maximum-scale=1.0,user-scalable=no"
    />
    <meta name="create" content="2023-11-01" />
    <meta name="desc" content="导航菜单底部border动效|熔岩灯" />
    <title>导航菜单底部border动效|熔岩灯</title>
  </head>
  <body>
    <ul class="menu" data-select="1">
      <li class="menu-item">首页</li>
      <li class="menu-item">猫猫真香</li>
      <li class="menu-item">今晚月色真美</li>
    </ul>
    <style>
      li {
        list-style: none;
        display: block;
      }

      body {
        background: #333;
      }
      .menu {
        margin: 0 auto;
        display: inline-flex;
        gap: 20px;
        padding: 20px 20px;
        background: #99f;
        white-space: nowrap;
        /* 组件化部分 */
        position: relative;
        --bw: 0;
        --bl: 0px;
      }

      /* 组件化部分 */
      .menu.active::after {
        content: '';
        height: 3px;
        background: rgb(209, 159, 10);
        width: var(--bw);
        position: absolute;
        left: var(--bl);
        bottom: 6px;
        transition:
          0.5s,
          opacity 1s;
        border-radius: 3;
      }
      .menu-item {
        cursor: pointer;
        color: #000;
      }
      .item-active{
        font-weight: bold;
      }
    </style>
    <script>
      const items = document.querySelectorAll('.menu .menu-item')
      const wrap = document.querySelector('.menu')
      //hover 时选中
      items.forEach((item) => {
        item.addEventListener('pointerenter', (e) => {
          selectItem(wrap, e.target)
        })
      })
      function selectItem(wrapElement, indexOrElement) {
        const item = Number.isInteger(indexOrElement)
          ? wrapElement.children[indexOrElement]
          : indexOrElement
        if (!item) return
        wrapElement.style.setProperty('--bw', item.offsetWidth + 'px')
        wrapElement.style.setProperty('--bl', item.offsetLeft + 'px')
      }
      const initSelect = parseInt(wrap.dataset.select ?? 0)
      selectItem(wrap, initSelect)
      //避免载入时：初始选中项下border移动
      setTimeout(() => {
        wrap.classList.add('active')
      }, 0)

      //额外效果:hover 时 select, 离开时选中click 过的
      function andClick() {
        let select = initSelect
        items.forEach((item) => {
          item.addEventListener('click', (e) => {
            select = e.target
            setItemsClass(e.target,'item-active')
          })
          item.addEventListener('pointerleave', (e) => {
            selectItem(wrap, select)
          })
        })
      }
      andClick()
      function setItemsClass(item,className){
        document.querySelectorAll(`.${className}`).forEach(target=>target.classList.remove(className))
        item.classList.add(className)
      }
    </script>
    <dl>
      <dt>启发</dt>
      <dd><a href="./GlowingCornerHoverEffects.html">GlowingCornerHoverEffects </a></dd>
    </dl>
    <dl>
      <dt>问题</dt>
      <dd>？载入时页面闪了？</dd>
      <dd>- 见代码 setTimeout 部分@line:79</dd>
      <dd>？andClick 后，会不会让用户迷惑，现在之前到底选中了没有</dd>
      <dd>- ? 选中后加粗</dd>
    </dl>
  </body>
</html>
